#include "app.h"

// Checa se os dados lidos da FLASH estão corretos
int check_Values(void) {
	//if ( (pPar->offset1 < minOFFSET*10) || (pPar->offset1 > maxOFFSET*10) ) return errOFFSET1;

	tParServo* parServo;
	int x; for(x=0;x<SERVO_N_MODULE;x++) {
		parServo = (tParServo*)control.servo[x].par;

		if ( (parServo->offset < 100) || (parServo->offset > 3000) ) return errSERVO_PAR_OFFSET;
		if ( (parServo->min < 100) || (parServo->min > 3000) ) return errSERVO_PAR_MIM;
		if ( (parServo->max < 100) || (parServo->max > 3000) ) return errSERVO_PAR_MAX;
	}

	return pdOK;
}

// ###########################################################################################
// VALORES PADRÕES
void par_ValuesDefaults(void) {
	#if (LOG_APP == pdON)
	plog("ALL VALUE DEFAULT"CMD_TERMINATOR);
	#endif

	//pPar->offset1 = stdOFFSET;

	tParServo* parServo;
	//tParServo* parServo = (tParServo*) control.s[relay].par;
	int x; for(x=0;x<SERVO_N_MODULE;x++) {
	parServo = (tParServo*)control.servo[x].par;
		control.servo[x].par[idxOFFSET]
	}
//
//	#if ( (WORKTEMP_MODEL == WORKTEMP_WT47) || (WORKTEMP_MODEL == WORKTEMP_WT47i) )
//		par_RelayDefaults(0, opCOLD);
//		par_RelayDefaults(1, opCOLD);
//		par_RelayDefaults(2, opCOLD);
//		par_RelayDefaults(3, opCOLD);
//	#elif ( (WORKTEMP_MODEL == WORKTEMP_WT48) || (WORKTEMP_MODEL == WORKTEMP_WT48i) )
//		par_RelayDefaults(0, opHEATER);
//		par_RelayDefaults(1, opNOP);
//		par_RelayDefaults(2, opNOP);
//		par_RelayDefaults(3, opNOP);
//	#else
//		par_RelayDefaults(0, opCOLD);
//		#if (nRELAY > 1)
//		par_RelayDefaults(1, opDEFROST);
//		#endif
//		#if (nRELAY > 2)
//		par_RelayDefaults(2, opFAN);
//		#endif
//		#if (nRELAY > 3)
//		par_RelayDefaults(3, opNOP);
//		#endif
//	#endif
//
//	temp_InitStatistic();
}

//void par_RelayDefaults(int relay, int op) {
//	int s1=0, s2=0;
//
//	if ((op == opDEFROST) || (op == opFAN)) s1 = 1;
//	// para timerif para o rele < 2 vai assumir sensor 2 e os demais sensor3
//	else if (op == opTIMERIF) {
//		if (relay < 2) s1 = 2; else s1 = 3;
//	}
//
//	if (op == opHEATER) s2 = 1;
//
//	tParRelay* pParRelay = (tParRelay*) control.relay[relay].par;
//	// Aplicar os valores padrões para cada rele dependendo do seu modo de operação
//	// e salva todos os parametros na EEPROM
//	pParRelay->op = op;
//
//	// os menus estão preparados para ajustar os limites de cada item baseados nos limites de seus dependentes.
//	// porém, no momento vamos usar os limites iguais para todos os itens e para não alterar a estrutura dos menus
//	//	estamos atualizando os limites dos menus aqui, não mude essa forma
//	pParRelay->lo = convCelcius2TempWork(minTEMP_WORK);
//	pParRelay->hi = convCelcius2TempWork(maxTEMP_WORK);
//	if (op == opALARM) {
//		pParRelay->tll = convCelcius2TempWork(10);
//		pParRelay->tlh = convCelcius2TempWork(40);
//	} else {
//		pParRelay->tll = convCelcius2TempWork(minTEMP_WORK);
//		pParRelay->tlh = convCelcius2TempWork(maxTEMP_WORK);
//	}
//	pParRelay->irl = 0; 	// Sem inversão do rele
//	pParRelay->sen1 = s1;
//	pParRelay->sen2 = s2;
//
//	if (op == opCOLD) {
//		#if ( (WORKTEMP_MODEL == WORKTEMP_WT47) || (WORKTEMP_MODEL == WORKTEMP_WT47i) )
//		if (relay == 0)			pParRelay->sp = convCelcius2TempWork(25);
//		else if (relay == 1)	pParRelay->sp = convCelcius2TempWork(30);
//		else if (relay == 2)	pParRelay->sp = convCelcius2TempWork(35);
//		else 					pParRelay->sp = convCelcius2TempWork(40);
//		pParRelay->dly = 0;
//		pParRelay->dt = 10;
//		#else
//		pParRelay->sp = convCelcius2TempWork(-2);
//		pParRelay->dly = 1;
//		pParRelay->dt = 20;
//		#endif
//
//		pParRelay->tlrs = 0;
//		pParRelay->pers = 0;
//		pParRelay->tiro = 0; // sem tempo minimo do rele ficar ligado
//
//	} else if ( (op == opHOT) || (op == opTIMERIF) ) {
//		pParRelay->sp = convCelcius2TempWork(20);
//		pParRelay->tlrs = 0;
//		pParRelay->pers = 0;
//		pParRelay->dly = 0;
//		pParRelay->tiro = 0; // sem tempo minimo do rele ficar ligado
//		pParRelay->dt = 20;
//	} else if (op == opALARM) {
//		#if (USES_ADVANCED_PARS == pdON)
//		pParRelay->dlyl = 60; // 60 segundos
//		pParRelay->dlyh = 60; // 60 segundos
//		#else
//		pParRelay->dlyl = 0; // desligado
//		pParRelay->dlyh = 0; // desligado
//		#endif
//		pParRelay->taof = 1; // 1 segundo, minimo 1 segundo
//		pParRelay->taon = 1; // 1 segundo, minimo 1 segundo
//	}
//
//	if (op == opDEFROST) {
//		pParRelay->sp = convCelcius2TempWork(4);
//		pParRelay->dini = 0; 		// não iniciar o degelo ao ligar o equipamento
//		pParRelay->dtyp = 0; 		// Tipo elétrico o degelo
//		pParRelay->dftc = 240; 	// Tempos em tempo de 240 minutos (4 horas) para início o degelo
//		pParRelay->dftd = 30; 	// Duração de 30 minutos o degelo
//		pParRelay->tirg = 0; 		// Sem tempo de retorno do gas liquido antes do degelo
//		pParRelay->drti = 10;		// 10 minutos de gotejamento depois do degelo
//	}
//
//	if (op == opFAN) {
//		pParRelay->spdl = convCelcius2TempWork(0);
//		pParRelay->spst = convCelcius2TempWork(40);
//		pParRelay->dfon = 0;		// Não ligar o ventilador durante o degelo
//		pParRelay->gfon = 1;		// Ligar o ventilador durante o recolhimento do gás
//		pParRelay->dly = 1;		// Um minuto de delay para que o ventilador entre a funcionar a partir do inicio da refrigeração
//		pParRelay->actr = 0;		// Ventilador sempre ligado durante a refrigeração
//	} else if ( (op == opTIMER) || (op == opTIMERIF) ) {
//		pParRelay->ttype = 0; // Tipo de termostato HOT para timerIF
//		s32* p = &pParRelay->tr_base;
//		*p++ = (240<<20) | (360<<8) | 0xFF;	// SET1 Ligar as 6 horas da manha por 4 horas todos os dias da semana
//		*p++ = (360<<8) | 0x7F; // SET2 Desligado
//		*p++ = (360<<8) | 0x7F; // SET3 Desligado
//		*p++ = (360<<8) | 0x7F; // SET4 Desligado
//	}
//
//	if (op == opHEATER) {
//		pParRelay->sp = convCelcius2TempWork(minSP_HEAT);
//		pParRelay->don = convCelcius2TempWork(8);
//		pParRelay->doff = convCelcius2TempWork(4);
//		pParRelay->tl = convCelcius2TempWork(4);
//		pParRelay->th = convCelcius2TempWork(60);
//		pParRelay->dt = convCelcius2TempWork(2);
//		pParRelay->dtr = convCelcius2TempWork(35);
//		pParRelay->ftube = 0; // sem uso do controle para coletor a vácuo
//	}
//
//	if (op == opAUX) pParRelay->surl = 1;
//
//	// Colocar o processo de controle do rele nas condições iniciais
//	//	Também é preciso reiniciar o processo de controle (tAction) no momento da mudança,
//	//	isto para garantir que o processo de controle esteja pronto quando o usuário só troque de operador
//	//	e não mexa nos parâmetros.
//	control_ResetRelay(relay, pdFALSE);
//}

// ###########################################################################################
// GERENCIAMENTO DE VALORES ARMAZENADOS NO FINAL DA FLASH DE PROGRAMA

// Lê valores de configurações na flash, caso não conter valores válidos, colocar valores padrões
// Também lê os logs de erros
void flash_Load(void) {
	int x, y;
	tDataFlash* p = (tDataFlash*) (0xf000);
	tLogFlash* pLog = (tLogFlash*) (0xe000);
	// calcular o CRC da flash
	u16 crc = crc16_MODBUS(p, (sizeof(tDataFlash))-2);

	// carregar os logs de erro
	tDataLog* pl = pLog->err;
	for(x=0;x<nLOG;x++) {
		// se o os valores da flash forem inválidos  (ID) ou o código for 0xFF, não há erro gravados
		if (pl->code == 0xFF) {
			control.err[x].countTick = 0;
			control.err[x].code = 0;
		} else {
			control.err[x].countTick = pl->countTick;
			control.err[x].code = pl->code;
		}
		pl++;
	}

	// Se o ID está correto e CRC errado, é porque houve algum erro de hardware ou durante a gravação
	if ( (crc != p->crc) && (p->id == idFLASH) ) {
		showVicError(errCRC_FLASH); // trava no loop sinalizando o erro
	// Se o CRC e o ID estão corretos vamos carregar todos os valores
	} if ( (crc == p->crc) && (p->id == idFLASH) )  {
		#if (LOG_APP == pdON)
		plog("LOAD FLASH id:0x%x crc:%d"CMD_TERMINATOR, p->id, p->crc);
		#endif

		//pPar->offset1 = p->par.offset1;

		tParServo* pserv = p->parServo;
		s32* par;
		for(x=0;x<SERVO_N_MODULE;x++) {
			par = &pserv->offset;
			for(y=0;y<nPAR_SERVO;y++) control.servo[x].par[y] = *par++;
			pserv++;
		}
	} else {
		// Todos os parametros assumirem valores padrões
		par_ValuesDefaults();
		flash_Save();
	}
}

// Salvas dados de calibração no final da flash
#include "vic.h"
int flash_Save(void) {
	int x,y;
	u8 dataBuf[lenFLASH];
	tDataFlash* p = (tDataFlash*) dataBuf;

	irq_Disable(); 		// Desabilitar interrupções

	for(x=0;x<lenFLASH;x++) dataBuf[x] = 0xFF;

	// Antes de gravar na flash é preciso preparar o setor para gravação
	if (iap_ClearSectors(15,15) != pdPASS) return pdFAIL;

	p->id = idFLASH;
	//p->par.offset1 = pPar->offset1;

	tParServo* pserv = p->parServo;
	s32* par;
	for(x=0;x<SERVO_N_MODULE;x++) {
		par = &pserv->offset;
		for(y=0;y<nPAR_SERVO;y++) *par++=control.servo[x].par[y];
		pserv++;
	}

	p->crc = crc16_MODBUS(dataBuf, (sizeof(tDataFlash))-2);

	// gravar na FLASH. Somente aceita buffers de tamanhos de 256, 512, 1024 ou 4096 KB dependendo do setor
	if (iap_WriteSectors (0xf000, (u8*)dataBuf, lenFLASH) != pdPASS) return pdFAIL;

	irq_Enable(); 	// Habilitar interrupções
	control.ticks = 0; // Inicializa o ticks para que o relé seja atracado navamente caso se demorou muito para gravar na flash

	#if (LOG_APP == pdON)
	plog("SAVE FLASH crc = %d"CMD_TERMINATOR, p->crc);
	#endif

	return pdPASS;
}

static int flash_SaveLog(void) {
	int x;
	u8 dataBuf[lenFLASH_LOG];
	tLogFlash* p = (tLogFlash*) dataBuf;

	for(x=0;x<lenFLASH_LOG;x++) dataBuf[x] = 0xFF;

	// Antes de gravar na flash é preciso preparar o setor para gravação
	if (iap_ClearSectors(14,14) != pdPASS) return pdFAIL;

	tDataLog* pl = p->err;
	for(x=0;x<nLOG;x++) {
		pl->countTick = control.err[x].countTick;
		pl->code = control.err[x].code;
		pl++;
	}

	p->crc = crc16_MODBUS(dataBuf, (sizeof(tLogFlash))-2);

	// gravar na FLASH. Somente aceita buffers de tamanhos de 256, 512, 1024 ou 4096 KB dependendo do setor
	if (iap_WriteSectors (0xe000, (u8*)dataBuf, lenFLASH_LOG) != pdPASS) return pdFAIL;

	return pdPASS;
}

// limpa os logs de erro
int flash_ClearLogError(void) {
	uint x; for(x=0; x<nLOG;x++) {
		control.err[x].countTick = 0;
		control.err[x].code = 0;
	}

	return flash_SaveLog();
}

// salva o erro no primeiro slot disponivel. Salvar na posição da FLASH diferente dos parametros
int flash_SaveLogError(u32 countTicks, u8 n) {
	int res = pdFALSE;

	// encontrar até um slot vazio, uma vez encontrado salva na flash e cai fora
	uint x; for(x=0; x<nLOG;x++)
		if (control.err[x].code == 0) {
			control.err[x].countTick = countTicks;
			control.err[x].code = n;
			res = flash_SaveLog();
			break;
		}

	return res;
}
